package com.hexb.smh.config.shiro;

import com.hexb.core.utils.Assert;
import com.hexb.smh.entity.Account;
import com.hexb.smh.entity.enums.RoleType;
import com.hexb.smh.entity.shiro.SmhUsernamePasswordToken;
import com.hexb.smh.exceptions.AccountNotMatchException;
import com.hexb.smh.service.IAccountService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author : hexb
 * 权限验证器
 */
@Component
public class SmhAuthorizingRealm extends org.apache.shiro.realm.AuthorizingRealm {

    @Autowired
    private IAccountService accountService;

    public SmhAuthorizingRealm() {
    }

    public SmhAuthorizingRealm(CacheManager cacheManager) {
        super(cacheManager);
    }

    public SmhAuthorizingRealm(CredentialsMatcher matcher) {
        super(matcher);
    }

    public SmhAuthorizingRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
        super(cacheManager, matcher);
    }


    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        Account user = (Account) principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        authorizationInfo.addRole(user.getRole().name());
        authorizationInfo.addRole(user.getActivated() ? "activated" : "un_activated");
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
            throws AuthenticationException {
        SmhUsernamePasswordToken upt = (SmhUsernamePasswordToken) authenticationToken;
        String loginName = authenticationToken.getPrincipal().toString();
        Account account = accountService.findByLoginNameOrPhoneNo(loginName);
        Assert.isNull(account, (args) -> {
            throw new UnknownAccountException();
        });

        boolean accountTypeIsMatch = (upt.getRole() == RoleType.admin && account.isAdmin())
                || (upt.getRole() == RoleType.salesman && account.isSalesman());
        Assert.isFalse(accountTypeIsMatch, (args) -> {
            throw new AccountNotMatchException();
        });

        Assert.isFalse(account.getEnabled(), (args) -> {
            throw new DisabledAccountException();
        });
        return new SimpleAuthenticationInfo(account, account.getPassword(), account.getLoginName());
    }

    @Autowired
    @Override
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        super.setCredentialsMatcher(credentialsMatcher);
    }
}
